package com.only.webServer;


import com.only.webServer.request.HttpRequest;
import com.only.webServer.request.RequestUtils;
import com.only.webServer.response.HttpResponse;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * http 服务器
 */
public class HttpServer {

    private ExecutorService pool;

    public HttpServer(int port) throws IOException {
        if (port < 1 || port > 65535) {
            throw new RuntimeException("端口不可用 port："+port);
        }
        pool = Executors.newFixedThreadPool(10);

        ServerSocket serverSocket = new ServerSocket(port);

        while (true) {
            // 接受请求
            Socket accept = serverSocket.accept();
            if (accept != null && !accept.isClosed()) {
                pool.submit(() -> {
                    try {
                        response(accept);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });
            }

        }
    }

    /**
     * 给客户端响应数据
     * @param accept
     * @throws IOException
     */
    private void response(Socket accept) throws IOException {
        // 套接字的输入输出流
        InputStream inputStream = accept.getInputStream();
        OutputStream outputStream = accept.getOutputStream();

        // 获取请求的报文
        String requestMessage = getRequestMessage(inputStream);
        if ("".equals(requestMessage)) {
            // 过滤无效的请求
            outputStream.write(new HttpResponse().out());
            outputStream.flush();
            outputStream.close();
            return;
        }
        HttpRequest httpRequest = RequestUtils.getHttpRequest(requestMessage);
        HttpResponse httpResponse = new HttpResponse();

        // 请求分发
        DispatcherServlet.dispense(httpRequest, httpResponse);
        outputStream.write(httpResponse.out());
        outputStream.flush();
        accept.close();
    }

    /**
     * 获取请求报文
     *
     * 这里的请求的输入流可能会阻塞
     * read()：如果因已到达流末尾而没有可用的字节，则返回值 -1
     * 在输入数据可用、检测到流的末尾或者抛出异常前，此方法一直阻塞
     *
     * 所以我们需要计算读取的次数，最后一次读取完后直接跳出不在读取流  否则会阻塞
     *
     *
     * @return 请求报文，转换成了String类型（二进制文件上传会有问题）
     */
    private String getRequestMessage(InputStream inputStream) throws IOException {
        // 读取请求输入流
        int i = 0;
        byte[] buff = new byte[1024];
        StringBuilder requestBuilder = new StringBuilder();
        // 用于计数，需要读取的次数
        double count = 1;
        String regex = "Content-Length: (\\d*)";
        Pattern pattern = Pattern.compile(regex);
        while (count > 0 && (i = inputStream.read(buff))>0) {
            count--;
            String s = new String(buff, 0, i);
            Matcher matcher = pattern.matcher(s);
            if (matcher.find()) {
                // 请求头的字节大小 （加四个是因为\r\n\r\n也占四字节）
                int headLength = s.indexOf("\r\n") + 4;
                // 请求体大小 如果是post请求含有请求体请求头上会携带Content-Length: 参数
                int contentLength = Integer.parseInt(matcher.group(1));
                // 计算要读取多少次（减一是因为第一次已经被读取了）
                count = Math.ceil((headLength + contentLength) * 1.0 /1024) - 1;
            }
            requestBuilder.append(s);
        }
        return requestBuilder.toString();
    }
}
